import 'package:common/network/code_msg_data_model.dart';
import 'package:common/network/custom_interceptor.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';

import '../constant/constant.dart';
import '../constant/http_constant.dart';
import '../utils/log_util.dart';
import 'business_response.dart';
import 'code_msg_model.dart';

///参照https://www.jianshu.com/p/6a8d857545f8
///网络请求管理
///
class DioManager {
  late BaseOptions options;

  late Dio _dio;

  static final DioManager _instance = DioManager._internal();

  ///工厂模式
  factory DioManager() => _instance;

  DioManager._internal() {
    _dio = Dio(initDefaultOptions(HttpConstant.baseUrl));
    initDefaultInterceptors();
  }

  DioManager.external(String baseUrl) {
    _dio = Dio(initDefaultOptions(baseUrl));
    initDefaultInterceptors();
  }

  Dio get dio => _dio;

  BaseOptions get dioOptions => _dio.options;

  ///配置默认的参数
  BaseOptions initDefaultOptions(String baseUrl) {
    BaseOptions options = BaseOptions();
    options.baseUrl = baseUrl;
    options.connectTimeout = const Duration(milliseconds: HttpConstant.httpConnectTimeout);
    options.receiveTimeout = const Duration(milliseconds: HttpConstant.httpReadTimeout);
    options.sendTimeout = const Duration(milliseconds: HttpConstant.httpWriteTimeout);
    return options;
  }

  ///配置默认的拦截器
  void initDefaultInterceptors() {
    dio.interceptors.add(CustomInterceptor());
    dio.interceptors.add(LogInterceptor(
        request: kDebugMode,
        requestHeader: kDebugMode,
        requestBody: kDebugMode,
        responseHeader: kDebugMode,
        responseBody: kDebugMode));
  }

  ///Get请求---通过路径
  ///path : api/login
  void httpGetByPath<D>(String urlPath, BusinessResponse businessResponse) async {
    Response? response;
    try {
      response = await dio.get<Map<String, dynamic>>(urlPath, cancelToken: businessResponse.onGetCancelToken());
      CodeMsgDataModel responseModel = CodeMsgDataModel.fromMap(response.data);
      if (responseModel.code == Constant.success.toString()) {
        businessResponse.onSuccess(responseModel.data, response.requestOptions.path);
      } else if (responseModel.code == Constant.logout.toString()) {
        businessResponse.onLogOut(responseModel);
      } else {
        businessResponse.onFail(responseModel);
      }
    } on DioException catch (dioException) {
      _handleDioException(businessResponse, dioException);
    } on Exception catch (exception) {
      _handleException(businessResponse, exception);
    }
  }
  ///Get请求---通过全路径
  ///uri : baseUrl + api/login
  void httpGetByUri(Uri url, BusinessResponse businessResponse) async {
    Response? response;
    try {
      response = await dio.getUri<Map<String, dynamic>>(url, cancelToken: businessResponse.onGetCancelToken());
      CodeMsgDataModel responseModel = CodeMsgDataModel.fromMap(response.data);
      if (responseModel.code == Constant.success.toString()) {
        businessResponse.onSuccess(responseModel.data, response.requestOptions.path);
      } else if (responseModel.code == Constant.logout.toString()) {
        businessResponse.onLogOut(responseModel);
      } else {
        businessResponse.onFail(responseModel);
      }
    } on DioException catch (dioException) {
      _handleDioException(businessResponse, dioException);
    } on Exception catch (exception) {
      _handleException(businessResponse, exception);
    }
  }

  ///Post请求---通过路径
  ///path : api/login
  void httpPostByPath(String urlPath, Object? bodyData, BusinessResponse businessResponse,{Map<String, dynamic>? queryParameters,ProgressCallback? onSendProgress}) async {
    Response? response;
    try {
      response = await dio.post<Map<String, dynamic>>(urlPath, data: bodyData, cancelToken: businessResponse.onGetCancelToken(),queryParameters: queryParameters,onSendProgress: onSendProgress);
      CodeMsgDataModel responseModel = CodeMsgDataModel.fromMap(response.data);
      if ((responseModel.code == Constant.success.toString())
          || responseModel.code == Constant.twoHundred.toString()) {
        businessResponse.onSuccess(responseModel.data, response.requestOptions.path);
      } else if (responseModel.code == Constant.logout.toString()) {
        businessResponse.onLogOut(responseModel);
      } else {
        businessResponse.onFail(responseModel);
      }
    } on DioException catch (dioException) {
      _handleDioException(businessResponse, dioException);
    } on Exception catch (exception) {
      _handleException(businessResponse, exception);
    }
  }
  ///Post请求---通过路径
  ///uri : baseUrl + api/login
  void httpPostByUri(Uri url, Object? bodyData, BusinessResponse businessResponse,{Map<String, dynamic>? queryParameters,ProgressCallback? onSendProgress}) async {
    Response? response;
    try {
      response = await dio.postUri<Map<String, dynamic>>(url, data: bodyData, cancelToken: businessResponse.onGetCancelToken(),onSendProgress: onSendProgress);
      CodeMsgDataModel responseModel = CodeMsgDataModel.fromMap(response.data);
      if (responseModel.code == Constant.success.toString()) {
        businessResponse.onSuccess(responseModel.data, response.requestOptions.path);
      } else if (responseModel.code == Constant.logout.toString()) {
        businessResponse.onLogOut(responseModel);
      } else {
        businessResponse.onFail(responseModel);
      }
    } on DioException catch (dioException) {
      _handleDioException(businessResponse, dioException);
    } on Exception catch (exception) {
      _handleException(businessResponse, exception);
    }
  }

  ///Post请求---通过路径
  ///path : api/login
  void downloadByPath(String urlPath, String savePath, BusinessResponse businessResponse,{Map<String, dynamic>? queryParameters,ProgressCallback? onReceiveProgress}) async {
    Response? response;
    try {
      response = await dio.download(urlPath, savePath,cancelToken: businessResponse.onGetCancelToken(),queryParameters: queryParameters,onReceiveProgress: onReceiveProgress);
      if(response.data is Map){
        CodeMsgDataModel responseModel = CodeMsgDataModel.fromMap(response.data);
        if (responseModel.code == Constant.success.toString()) {
          businessResponse.onSuccess(responseModel.data, response.requestOptions.path);
        } else if (responseModel.code == Constant.logout.toString()) {
          businessResponse.onLogOut(responseModel);
        } else {
          businessResponse.onFail(responseModel);
        }
      }else if(response.data is ResponseBody){
        businessResponse.onSuccess(response.data, response.requestOptions.path);
      }
    } on DioException catch (dioException) {
      _handleDioException(businessResponse, dioException);
    } on Exception catch (exception) {
      _handleException(businessResponse, exception);
    }
  }

  ///Post请求---通过路径
  ///uri : baseUrl + api/login
  void downloadByUri(Uri uri,String savePath, BusinessResponse businessResponse,{ProgressCallback? onReceiveProgress}) async {
    Response? response;
    try {
      response = await dio.downloadUri(uri, savePath,cancelToken: businessResponse.onGetCancelToken(),onReceiveProgress: onReceiveProgress);
      if(response.data is Map){
        CodeMsgDataModel responseModel = CodeMsgDataModel.fromMap(response.data);
        if (responseModel.code == Constant.success.toString()) {
          businessResponse.onSuccess(responseModel.data, response.requestOptions.path);
        } else if (responseModel.code == Constant.logout.toString()) {
          businessResponse.onLogOut(responseModel);
        } else {
          businessResponse.onFail(responseModel);
        }
      } else if (response.data is ResponseBody) {
        businessResponse.onSuccess(response.data, response.requestOptions.path);
      }
    } on DioException catch (dioException) {
      _handleDioException(businessResponse, dioException);
    } on Exception catch (exception) {
      _handleException(businessResponse, exception);
    }
  }

  void _handleDioException(BusinessResponse businessResponse, DioException dioException) {
    CodeMsgModel codeMsgModel = CodeMsgModel();
    codeMsgModel.code = dioException.response != null
        ? dioException.response?.statusCode.toString()
        : Constant.fail.toString();
    codeMsgModel.msg = dioException.response != null
        ? dioException.response?.statusMessage
        : (dioException.message ?? (dioException.error?.toString() ?? dioException.type.name));
    businessResponse.onFail(codeMsgModel);
  }

  void _handleException(BusinessResponse businessResponse, Exception exception) {
    LogUtil.stdPrint(exception);
    CodeMsgModel codeMsgModel = CodeMsgModel();
    codeMsgModel.code = Constant.fail.toString();
    codeMsgModel.msg = exception.toString();
    businessResponse.onFail(codeMsgModel);
  }
}
